from . import passport_blu
from flask import request, abort, make_response, jsonify,session
from info.utils.captcha.captcha import captcha
from info import redis_store, constants,db
from info.utils import response_code
import logging, re, random,datetime
from info.lib.yuntongxun.sms import CCP
from info.models import User



@passport_blu.route('/logout')
def logout():
    """退出登录
    1.只需要将状态保持信息删除即可(退出登录的方案有很多，但是核心的思想是清除session)
    2.返回退出登录的结果
    """
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)

    # 2.返回退出登录的结果
    return jsonify(errno=response_code.RET.OK, errmsg='退出登录成功')


@passport_blu.route('/login', methods=['POST'])
def login():
    """登录
    1.接受参数：mobile, password(明文)
    2.校验参数：参数是否齐全，校验手机号码格式是否正确
    3.使用mobile查询user是否存在
    4.如果user存在，再去校验密码
    5.如果密码校验通过，就记录最后一次登录的时间和状态保持
    6.响应登录结果
    """
    # 1.接受参数：mobile, password(明文)
    json_dict = request.json
    mobile = json_dict.get('mobile')
    password = json_dict.get('password')

    # 2.校验参数：参数是否齐全，校验手机号码格式是否正确
    if not all([mobile, password]):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='缺少必传参数')
    if not re.match('^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='手机号格式错误')

    # 3.使用mobile查询user是否存在
    try:
        user = User.query.filter(User.mobile==mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='用户名或密码错误')
    if not user:
        return jsonify(errno=response_code.RET.NODATA, errmsg='用户名或密码错误')

    # 4.如果user存在，再去校验密码
    if not user.check_password(password):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='用户名或密码错误')

    # 5.如果密码校验通过，就记录最后一次登录的时间和状态保持
    user.last_login = datetime.datetime.now()
    try:
        db.session.commit() # 修改记录不需要add
    except Exception as e:
        logging.error(e)
        db.session.rollback()
        return jsonify(errno=response_code.RET.DATAERR, errmsg='登录失败')

    # 状态保持
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 6.响应登录结果
    return jsonify(errno=response_code.RET.OK, errmsg='登录成功')


@passport_blu.route('/register', methods=['POST'])
def register():
    """注册
    1.接受参数：mobile, smscode, password(明文)
    2.校验参数：参数是否齐全，校验手机号码格式是否正确
    3.使用mobile读取redis中短信验证码
    4.使用客户端传入的短信验证码和服务器短信验证码进行对比
    5.创建User模型对象,并给用户属性赋值
    6.记得保存最后一次登录的时间（last_login,为了实现注册即登录）
    7.需要将用户注册数据保存到mysql数据库
    8.将状态保持信息写入到session(为了实现注册即登录)
    9.返回注册结果
    """
    # 1.接受参数：mobile, smscode, password(明文)
    json_dict = request.json
    mobile = json_dict.get('mobile')
    sms_code_client = json_dict.get('smscode')
    password = json_dict.get('password')

    # 2.校验参数：参数是否齐全，校验手机号码格式是否正确
    if not all([mobile, sms_code_client, password]):
        return jsonify(errno=response_code.RET.PARAMERR,errmsg='缺少必传参数')
    if not re.match('^1[345678][0-9]{9}$',mobile):
        return jsonify(errno=response_code.RET_PARAMERR,errmsg='手机号格式错误')

    # 3.使用mobile读取redis中短信验证码
    try:
        sms_code_server = redis_store.get('SMS:' + mobile)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET_DBERR,errmsg='查询短信验证码失败')
    if not sms_code_server:
        return jsonify(errno=response_code.RET.NODATA, errmsg='短信验证码不存在')

    # 4.使用客户端传入的短信验证码和服务器短信验证码进行对比
    if sms_code_client != sms_code_server:
        return jsonfiy(errno=response_code.RET_PARAMERR,errmsg='短信验证码输入有误')

    # 5.创建User模型对象,并给用户属性赋值
    user = User()
    user.nick_name = mobile # 默认手机号就是用户名
    user.mobile = mobile

    # user.password_hash = password # password 是明文，而password_hash需要存储密文
    # password : 是我即将给User模型类增加的属性（python是面向对象的高级编程语言，可以在代码运行的过程中给对象添加属性）
    # 再在password属性的setter方法中，拿着明文密码进行加密处理，再保存到password_hash
    user.password = password

    # 6.记得保存最后一次登录的时间（last_login,为了实现注册即登录）
    user.last_login = datetime.datetime.now() # 最后一次登录时间(实现注册即登录)

    # 7.需要将用户注册数据保存到mysql数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        logging.error(e)
        db.session.rollback()
        return jsonify(errno=response_code.RET_DATAERR,errmsg='存储用户数据失败')

    # 8.将状态保持信息写入到session(为了实现注册即登录)
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 9.返回注册结果
    return jsonify(erron=response_code.RET.OK,errmsg='注册成功')

@passport_blu.route('/sms_code', methods=['POST'])
def send_sms_code():
    """发送短信验证码
    1.接受参数：mobile, image_code, image_code_id
    2.校验参数：判断参数是否齐全，判断手机号格式是否正确
    3.使用image_code_id从redis中读取出服务器存储的图片验证码
    4.使用用户输入的图片验证码 对比 服务器存储的图片验证码
    5.如果对比成功生成短信验证码，长度是6位的随机数字
    6.再使用CCP()单例发送短信验证码
    7.发送短信验证码成功，就把短信验证码存储到redis()
    8.返回短信验证码发送的结果
    """
    # 1.接受参数：mobile, image_code, image_code_id
    json_dict = request.json
    mobile = json_dict.get('mobile')
    image_code_client = json_dict.get('image_code')
    image_code_id = json_dict.get('image_code_id')

    # 2.校验参数：判断参数是否齐全，判断手机号格式是否正确
    if not all([mobile, image_code_client, image_code_id]):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='缺少必传参数')
    if not re.match('^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='手机号格式错误')

    try:
        image_code_server = redis_store.get('ImageCode:' + image_code_id)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='查询图片验证码失败')
    # 判断image_code_server是否存在
    if not image_code_server:
        return jsonify(errno=response_code.RET.NODATA, errmsg='图片验证码不存在')

    # 4.使用用户输入的图片验证码 对比 服务器存储的图片验证码
    if image_code_client.lower() != image_code_server.lower():
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='图片验证码输入有误')

    # 5.如果对比成功生成短信验证码，长度是6位的随机数字,不够6位补0
    sms_code = '%06d' % random.randint(0, 999999)
    logging.debug(sms_code)

    # 6.再使用CCP()单例发送短信验证码
    result = CCP().send_sms_code(mobile, [sms_code, 5], 1)
    print(sms_code)
    print(mobile)
    if result != 0:
        return jsonify(errno=response_code.RET.THIRDERR, errmsg='发送短信失败')

    # 7.发送短信验证码成功，就把短信验证码存储到redis()
    try:
        redis_store.set('SMS:' + mobile, sms_code, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.DATAERR, errmsg='存储短信失败')

    # 8.返回短信验证码发送的结果
    return jsonify(errno=response_code.RET.OK, errmsg='发送短信成功')

@passport_blu.route('/image_code')
def get_image_code():
    """提供图片验证码
        1.接受参数：imageCodeId (UUID,图片验证码唯一标识符)
        2.校验参数：必须传入imageCodeId
        3.生成图片验证码的文字和图片信息
        4.将imageCodeId和图片验证码文字绑定到redis
        5.响应图片验证码的图片信息给用户
        """
    #1.接受参数： imageCodeId （UUID,图片验证码唯一标识符）
    image_code_id = request.args.get('code_id')

    # 2.校验参数：必须传入imageCodeId
    if not image_code_id:
        abort(400)

    # 3.生成图片验证码的文字和图片信息:text是图片验证码的文字；image是图片验证码图片
    # 注意点： 需要在虚拟环境中安装Pillow模块
    name,text,image = captcha.generate_captcha()

    # 4.将imageCodeId和图片验证码文字绑定到redis:图片验证码五分钟之后自动的过期
    try:
        redis_store.set('ImageCode:' + image_code_id,text,constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        logging.error(e)
        abort(500)# 表示服务器错误的

        # 5.响应图片验证码的图片信息给用户
        # 将image作为响应体
    response = make_response(image)
    # 指定响应体数据的类型
    response.headers['Content-Type'] = 'image/jpg'
    return response